
namespace Behemoth.SharePoint.Utilities {

    using System;
    using System.Runtime.InteropServices;
    using System.IO;
    using System.Collections.Generic;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Security;
    using System.Security.Permissions;
    using System.Globalization;

    using Microsoft.Win32;
    using Microsoft.SharePoint;
    using SPAdmin=Microsoft.SharePoint.Administration;
    using Microsoft.SharePoint.WebPartPages;
    using Microsoft.SharePoint.Deployment;
    using Microsoft.SharePoint.Security;

    using Behemoth.Configuration;
    using Behemoth.SharePoint.Configuration;
    using Behemoth.SharePoint.Logging;

    /// <summary>
    /// 
    /// </summary>
    /// <remarks>
    /// ReceiverAssembly="Behemoth.SharePoint.ARK, Version=1.?.?.?, Culture=neutral, PublicKeyToken=ecab56691def8148"
    /// ReceiverClass="Behemoth.SharePoint.Receivers.CustomPropertyRepair_FeatureReceiver"
    /// </remarks>
	[Guid( "ADDECF3A-D457-45f0-BCE7-1824CCDC5A48" )]
    public class CustomPropertyRepair_FeatureReceiver : SPFeatureReceiver {

        #region Logging Code Pattern v2.0

        ////private ULSTraceLogging logWriter;

        protected string LOGGING_PRODUCT { get { return "Behemoth"; } }
        protected string LOGGING_CATEGORY { get { return "Provisioning"; } }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        public event LoggingEventHandler Logging;

        /// <summary>
        /// Put a method like this in your class that produces log entries
        /// </summary>
        /// <param name="e"></param>
        public void Log(LoggingEventArgs e) {
            // if nobody could be bothered to attach their own events, we should
            // still log things in the default way
            if (Logging == null)
                Logging += new LoggingEventHandler(ULSTraceLogging.Default.Log);
            if (Logging != null)
                Logging(this, e);
        }
        public void Log(string msg) {
            Log(msg, TraceSeverity.InformationEvent);
        }
        public void Log(string msg, TraceSeverity severity) {
            LoggingEventArgs e = new LoggingEventArgs(LOGGING_CATEGORY, LOGGING_PRODUCT, msg, severity);
            Log(e);
        }
        public void Log(Exception ex) {
            LoggingEventArgs e = new LoggingEventArgs(LOGGING_CATEGORY, LOGGING_PRODUCT, ex);
            Log(e);
        }

        #endregion

        private CustomPropertyRepairFeatureProperties props;
        public CustomPropertyRepairFeatureProperties TypedProperties {
            get { return props; }
        }

        private void EnsureProperties(SPFeatureReceiverProperties properties) {
            Log("Invoking EnsureProperties.");
            if (props == null)
                props = new CustomPropertyRepairFeatureProperties(properties);
            else if (props.InitStatus != Status.Initialized)
                throw new Exception("property reader is not initialized. Can't continue.");
            Log("Leaving EnsureProperties.");
        }

		public CustomPropertyRepair_FeatureReceiver() : base() { }

		[SharePointPermission( SecurityAction.LinkDemand, ObjectModel = true )]
		public override void FeatureActivated( SPFeatureReceiverProperties properties ) {
            EnsureProperties(properties);
			this.OnActivated( properties );
		}

		[SharePointPermission( SecurityAction.LinkDemand, ObjectModel = true )]
		public override void FeatureDeactivating( SPFeatureReceiverProperties properties ) {
		}

		[SharePointPermission( SecurityAction.LinkDemand, ObjectModel = true )]
		public override void FeatureInstalled( SPFeatureReceiverProperties properties ) {
		}

		[SharePointPermission( SecurityAction.LinkDemand, ObjectModel = true )]
		public override void FeatureUninstalling( SPFeatureReceiverProperties properties ) {
		}

		/// <summary>
		///  Define your own feature activation action code here
		/// </summary>
		public void OnActivated( SPFeatureReceiverProperties properties ) {
            foreach (string filePath in this.TypedProperties.FieldPropertyDefinitionFiles) {
                string fileName = CheckFileName(filePath);
                ProcessCustomizatinFile(fileName);
			} // foreach
		}

        /// <summary>
        /// If it was an absolute path, cool, if not assume it is a sub-path of TEMPLATES folder
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private static string CheckFileName(string filePath) {
            string fileName = filePath;
            if (!File.Exists(fileName)) {
                string templateDir = SPFeatureXmlTools.GetTemplateFilePath(@"XML\CustomPropertyWorkaround"); //ProvisioningTools.GetSharePointTemplateDirectory();
                if (!string.IsNullOrEmpty(templateDir))
                    fileName = Path.Combine(templateDir, fileName);
            }
            if (!File.Exists(fileName))
                throw new FileNotFoundException(string.Format("CustomPropertyRepair_FeatureReceiver could not find the specified file '{0}'.", fileName));
            return fileName;
        }

        private void ProcessCustomizatinFile(string fileName) {
            // TODO consider improving this to use Linq instead
            //XmlDocument xDoc = new XmlDocument();
            //xDoc.Load( filePath );
            FileStream fs = new FileStream(fileName, FileMode.Open);
            XmlSerializer ser = new XmlSerializer(typeof(Customization));
            object o = ser.Deserialize(fs);
            Customization cust = o as Customization;

            if (this.TypedProperties.Web != null)
                cust.FixCustomProperties(this.TypedProperties.Web);
            if (this.TypedProperties.Site != null)
                cust.FixCustomProperties(this.TypedProperties.Site.RootWeb);
        }

	} // class
} // namespace